home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1995 May / macformat-024.iso / Shareware City / Developers / Kant Pro source Folder / Kant Pro 1.1 ƒ / Shell ƒ / drag utilities.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-01-23  |  20.5 KB  |  917 lines  |  [TEXT/MMCC]

  1. /* Note: dragging will not work properly if you compile and run this for native PowerMac.  I
  2.    am working on figuring out what I'm doing wrong.  -MP 1/23/95 */
  3.  
  4. #include "drag utilities.h"
  5. #include "graphics.h"
  6. #include "window layer.h"
  7. #include "text twiddling.h"
  8. #include <Folders.h>
  9. #include <GestaltEQU.h>
  10.  
  11. static    long        caretTime;
  12. static    short        caretOffset, caretShow, lastOffset, insertPosition, canAcceptItems;
  13. static    short        cursorInContent;
  14. static    Boolean        gDragManagerInstalled;
  15.  
  16. /*
  17.  *    The following #define statement provides access to TextEdit's caretTime.
  18.  */
  19.  
  20. #define    gCaretTime        ((short) *((long *) 0x02F4))
  21.  
  22. void InitTheDragManager(void)
  23. {
  24.     long            gestaltResponse;
  25.     
  26.     gDragManagerInstalled=TRUE;
  27.     if ((Gestalt(gestaltDragMgrAttr, &gestaltResponse) != noErr) ||
  28.         (!(gestaltResponse & (1 << gestaltDragMgrPresent))))
  29.     {
  30.         gDragManagerInstalled=FALSE;
  31.     }
  32. }
  33.  
  34. Boolean DragManagerAvailableQQ(void)
  35. {
  36.     return gDragManagerInstalled;
  37. }
  38.  
  39. /*
  40.  *    TEIsFrontOfLine, given an offset and a TextEdit handle, returns true if
  41.  *    the given offset is at the beginning of a line start.
  42.  */
  43.  
  44. short TEIsFrontOfLine(short offset, TEHandle theTE)
  45. {
  46.     short        line = 0;
  47.  
  48.     if ((**theTE).teLength == 0)
  49.         return(true);
  50.  
  51.     if (offset >= (**theTE).teLength)
  52.         return( (*((**theTE).hText))[(**theTE).teLength - 1] == 0x0d );
  53.  
  54.     while ((**theTE).lineStarts[line] < offset)
  55.         line++;
  56.  
  57.     return( (**theTE).lineStarts[line] == offset );
  58. }
  59.  
  60. /*
  61.  *    TEGetLine, given an offset and a TextEdit handle, returns the line number
  62.  *    of the line that contains the offset.
  63.  */
  64.  
  65. short TEGetLine(short offset, TEHandle theTE)
  66. {
  67.     short        line = 0;
  68.  
  69.     if (offset > (**theTE).teLength)
  70.         return((**theTE).nLines);
  71.  
  72.     while ((**theTE).lineStarts[line] < offset)
  73.         line++;
  74.     
  75.     return(line);
  76. }
  77.  
  78. /*
  79.  *    Given a point in global coordinates, HitTest returns a pointer to a
  80.  *    document structure if the point is inside a document window on the screen.
  81.  *    If the point is not inside a document window, HitTest return NULL in
  82.  *    theDoc. If the point is in a doument window and also in the viewRect of
  83.  *    the document's TextEdit field, HitTest also returns the offset into
  84.  *    the text that corresponds to that point. If the point is not in the text,
  85.  *    HitTest returns -1.
  86.  */
  87.  
  88. short HitTest(Point theLoc, WindowPtr *theWindow)
  89. {
  90.     short            offset;
  91.     TEHandle        hTE;
  92.     
  93.     *theWindow=0L;
  94.     offset = -1;
  95.  
  96.     if (FindWindow(theLoc, theWindow) == inContent)
  97.     {
  98.         SetPort(*theWindow);
  99.         GlobalToLocal(&theLoc);
  100.         hTE=GetWindowTE(*theWindow);
  101.         
  102. //        if ((PtInRect(theLoc, &((**hTE).viewRect))) && PtInRect(theLoc, &((**hTE).destRect)))
  103.         if (PtInRect(theLoc, &((**hTE).viewRect)))
  104.         {
  105.             offset=TEGetOffset(theLoc, hTE);
  106.             if ((TEIsFrontOfLine(offset, hTE)) && (offset) &&            
  107.                     ((*((**hTE).hText))[offset - 1] != 0x0D) &&
  108.                     (TEGetPoint(offset - 1, hTE).h < theLoc.h)) {
  109.                 offset--;
  110.             }
  111.         }
  112.     }
  113.  
  114.     return offset;
  115. }
  116.  
  117.  
  118. /*
  119.  *    DrawCaret draws a caret in a TextEdit field at the given offset. DrawCaret
  120.  *    expects the port to be set to the port that the TextEdit field is in.
  121.  *    DrawCaret inverts the image of the caret onto the screen.
  122.  */
  123.  
  124. void DrawCaret(short offset, TEHandle theTE)
  125. {
  126.     Point        theLoc;
  127.     short        theLine, lineHeight;
  128.  
  129.     /*
  130.      *    Get the coordinates and the line of the offset to draw the caret.
  131.      */
  132.  
  133.     theLoc  = TEGetPoint(offset, theTE);
  134.     theLine = TEGetLine(offset, theTE);
  135.  
  136.     /*
  137.      *    For some reason, TextEdit dosen't return the proper coordinates
  138.      *    of the last offset in the field if the last character in the record
  139.      *    is a carriage return. TEGetPoint returns a point that is one line
  140.      *    higher than expected. The following code fixes this problem.
  141.      */
  142.  
  143.     if ((offset == (**theTE).teLength) &&
  144.             (*((**theTE).hText))[(**theTE).teLength - 1] == 0x0D) {
  145.         theLoc.v += TEGetHeight(theLine, theLine, theTE);
  146.     }
  147.  
  148.     /*
  149.      *    Always invert the caret when drawing.
  150.      */
  151.  
  152.     PenMode(patXor);
  153.  
  154.     /*
  155.      *    Get the height of the line that the offset points to.
  156.      */
  157.  
  158.     lineHeight = TEGetHeight(theLine, theLine, theTE);
  159.  
  160.     /*
  161.      *    Draw the appropriate caret image.
  162.      */
  163.  
  164.     MoveTo(theLoc.h - 1, theLoc.v - 1);
  165.     Line(0, 1 - lineHeight);
  166.  
  167.     PenNormal();
  168. }
  169.  
  170. #if USE_STYLED_TEXT
  171. void InsertTextAtOffset(short offset, char *theBuf, long size, StScrpHandle theStyl, TEHandle theTE)
  172. #else
  173. void InsertTextAtOffset(short offset, char *theBuf, long size, TEHandle theTE)
  174. #endif
  175. {
  176.     if (size == 0)
  177.         return;
  178.  
  179.     TESetSelect(offset, offset, theTE);
  180. #if USE_STYLED_TEXT
  181.     TEStylInsert(theBuf, size, theStyl, theTE);
  182. #else
  183.     TEInsert(theBuf, size, theTE);
  184. #endif
  185.     TESetSelect(offset, offset + size, theTE);
  186. }
  187.  
  188. short GetSelectionSize(WindowPtr theWindow)
  189. {
  190.     TEHandle        hTE;
  191.     
  192.     hTE=GetWindowTE(theWindow);
  193.     return((**hTE).selEnd - (**hTE).selStart);
  194. }
  195.  
  196. Ptr GetSelectedTextPtr(WindowPtr theWindow)
  197. {
  198.     TEHandle        hTE;
  199.     
  200.     hTE=GetWindowTE(theWindow);
  201.     return((*(**hTE).hText) + (**hTE).selStart);
  202. }
  203.  
  204. #if USE_STYLED_TEXT
  205. /*
  206.  *    MySendDataProc
  207.  *
  208.  *    Will provide 'styl' data for the drag when requested.
  209.  */
  210.  
  211. pascal OSErr MySendDataProc(FlavorType theType, void *refCon,
  212.                             ItemReference theItem, DragReference theDrag)
  213. {
  214.     WindowPtr        theWindow=(WindowPtr)refCon;
  215.     StScrpHandle    theStyl;
  216.     TEHandle        hTE;
  217.     
  218.     hTE=GetWindowTE(theWindow);
  219.     if (theType == 'styl')
  220.     {
  221.         theStyl = GetStylScrap(hTE);
  222.  
  223.         //
  224.         //    Call SetDragItemFlavorData to provide the requested data.
  225.         //
  226.  
  227.         HLock((Handle) theStyl);
  228.         SetDragItemFlavorData(theDrag, theItem, 'styl', (Ptr) *theStyl,
  229.                               GetHandleSize((Handle) theStyl), 0L);
  230.         HUnlock((Handle) theStyl);
  231.         DisposeHandle((Handle) theStyl);
  232.  
  233.     } else {
  234.  
  235.         return(badDragFlavorErr);
  236.  
  237.     }
  238.  
  239.     return(noErr);
  240. }
  241. #endif
  242.  
  243. /*
  244.  *    MyReceiveDropHandler
  245.  *
  246.  *    Called by the Drag Manager when a drop occurs over one of the document windows.
  247.  */
  248.  
  249. pascal OSErr MyReceiveDropHandler(WindowPtr duhWindow, unsigned long handlerRefCon,
  250.                                   DragReference theDrag)
  251. {    OSErr            result;
  252.     TEHandle        tempTE;
  253.     Rect            theRect;
  254.     unsigned short    items, index;
  255.     ItemReference    theItem;
  256.     DragAttributes    attributes;
  257.     Ptr                textData;
  258.     Size            textSize;
  259. #if USE_STYLED_TEXT
  260.     Size            stylSize;
  261.     StScrpHandle    stylHandle;
  262. #endif
  263.     short            offset, selStart, selEnd, mouseDownModifiers, mouseUpModifiers, moveText;
  264.     WindowPtr        theWindow;
  265.     TEHandle        hTE;
  266.     
  267.     if ((!canAcceptItems) || (insertPosition == -1))
  268.         return(dragNotAcceptedErr);
  269.  
  270.     SetPort(duhWindow);
  271.     theWindow=(WindowPtr)handlerRefCon;
  272.     hTE=GetWindowTE(theWindow);
  273.     
  274.     GetDragAttributes(theDrag, &attributes);
  275.     GetDragModifiers(theDrag, 0L, &mouseDownModifiers, &mouseUpModifiers);
  276.  
  277.     moveText = (attributes & dragInsideSenderWindow) &&
  278.                (!((mouseDownModifiers & optionKey) | (mouseUpModifiers & optionKey)));
  279.  
  280.     //
  281.     //    Loop through all of the drag items contained in this drag and collect the text
  282.     //    into the tempTE record.
  283.     //
  284.  
  285.     SetRect(&theRect, 0, 0, 0, 0);
  286. #if USE_STYLED_TEXT
  287.     tempTE = TEStylNew(&theRect, &theRect);
  288. #else
  289.     tempTE = TENew(&theRect, &theRect);
  290. #endif
  291.  
  292.     CountDragItems(theDrag, &items);
  293.  
  294.     for (index = 1; index <= items; index++)
  295.     {
  296.         //
  297.         //    Get the item's reference number, so we can refer to it.
  298.         //
  299.  
  300.         GetDragItemReferenceNumber(theDrag, index, &theItem);
  301.  
  302.         //
  303.         //    Try to get the flags for a 'TEXT' flavor. If this returns noErr,
  304.         //    then we know that a 'TEXT' flavor exists in the item.
  305.         //
  306.  
  307.         result = GetFlavorDataSize(theDrag, theItem, 'TEXT', &textSize);
  308.  
  309.         if (result == noErr)
  310.         {
  311.  
  312.             textData = NewPtr(textSize);
  313.             if (textData == 0L)
  314.             {
  315.                 TEDispose(tempTE);
  316.                 return(memFullErr);
  317.             }
  318.  
  319.             GetFlavorData(theDrag, theItem, 'TEXT', textData, &textSize, 0L);
  320.  
  321. #if USE_STYLED_TEXT
  322.             //
  323.             //    Check for optional styl data for the TEXT.
  324.             //
  325.  
  326.             stylHandle = 0L;
  327.             result = GetFlavorDataSize(theDrag, theItem, 'styl', &stylSize);
  328.             if (result == noErr) {
  329.  
  330.                 stylHandle = (StScrpHandle) NewHandle(stylSize);
  331.                 if (stylHandle == 0L) {
  332.                     TEDispose(tempTE);
  333.                     DisposePtr(textData);
  334.                     return(memFullErr);
  335.                 }
  336.  
  337.                 HLock((Handle) stylHandle);
  338.                 GetFlavorData(theDrag, theItem, 'styl', *stylHandle, &stylSize, 0L);
  339.                 HUnlock((Handle) stylHandle);
  340.  
  341.             }
  342. #endif
  343.  
  344.             //
  345.             //    Insert this drag item's text into the tempTE.
  346.             //
  347.  
  348.             TESetSelect(32767, 32767, tempTE);
  349. #if USE_STYLED_TEXT
  350.             TEStylInsert(textData, textSize, stylHandle, tempTE);
  351. #else
  352.             TEInsert(textData, textSize, tempTE);
  353. #endif
  354.             DisposePtr(textData);
  355. #if USE_STYLED_TEXT
  356.             if (stylHandle)
  357.                 DisposeHandle((Handle) stylHandle);
  358. #endif
  359.         }
  360.     }
  361.  
  362.     //
  363.     //    Pull the TEXT and styl data out of the tempTE handle.
  364.     //
  365.  
  366.     textData = NewPtr(textSize = (**tempTE).teLength);
  367.     if (textData == 0L) {
  368.         TEDispose(tempTE);
  369.         return(memFullErr);
  370.     }
  371.     BlockMove(*(**tempTE).hText, textData, textSize);
  372.  
  373. #if USE_STYLED_TEXT
  374.     TESetSelect(0, 32767, tempTE);
  375.     stylHandle = GetStylScrap(tempTE);
  376. #endif
  377.  
  378.     TEDispose(tempTE);
  379.  
  380.     /* if we got any text, insert it */
  381.     if (textSize != 0)
  382.     {
  383.         /* remove caret and/or highlighting if necessary */
  384.         offset = caretOffset;
  385.         if (caretOffset != -1)
  386.         {
  387.             DrawCaret(caretOffset, hTE);
  388.             caretOffset = -1;
  389.         }
  390.         if (attributes & dragHasLeftSenderWindow)
  391.         {
  392.             HideDragHilite(theDrag);
  393.         }
  394.  
  395.         /* if drag occurred completely within one window which is not frontmost, bring the
  396.            window to the front and update its contents */
  397.         if ((attributes & dragInsideSenderWindow) && (theWindow != GetFrontDocumentWindow()))
  398.         {
  399.             MySelectWindow(theWindow);
  400.             UpdateTheWindow(theWindow);
  401.             TEActivate(hTE);
  402.         }
  403.  
  404.         /* activate TE if not already active; otherwise hiliting will screw up */
  405.         if (!((WindowPeek)theWindow)->hilited)
  406.         {
  407.             TEActivate(hTE);
  408.         }
  409.  
  410.         /* if this window is also the sender, delete source selection if option key isn't down */
  411.         if (moveText)
  412.         {
  413.             selStart = (**hTE).selStart;
  414.             selEnd   = (**hTE).selEnd;
  415.             if (insertPosition > selStart)
  416.             {
  417.                 insertPosition -= ((**hTE).selEnd - (**hTE).selStart);
  418.             }
  419.             
  420.             TEDelete(hTE);
  421.         }
  422.  
  423.         /* finally actually insert text */
  424. #if USE_STYLED_TEXT
  425.         InsertTextAtOffset(insertPosition, textData, textSize, stylHandle, hTE);
  426. #else
  427.         InsertTextAtOffset(insertPosition, textData, textSize, hTE);
  428. #endif
  429.  
  430.         /* update internal bits of window data */
  431.         ResetHiliteRgn(theWindow);
  432.         if (GetWindowVScrollBar(theWindow)!=0L)
  433.             AdjustVScrollBar(GetWindowVScrollBar(theWindow), hTE);
  434.         SetWindowIsModified(theWindow, TRUE);
  435.     }
  436.  
  437.     DisposePtr(textData);
  438.  
  439. #if USE_STYLED_TEXT
  440.     if (stylHandle)
  441.         DisposeHandle((Handle) stylHandle);
  442. #endif
  443.  
  444.     /* undo the forced TE activation, if necessary */
  445.     if (!((WindowPeek)theWindow)->hilited)
  446.     {
  447.         TEDeactivate(hTE);
  448.     }
  449.  
  450.     return noErr;
  451. }
  452.  
  453.  
  454. /*
  455.  *    MyTrackingHandler
  456.  *
  457.  *    This is the drag tracking handler for windows.
  458.  */
  459.  
  460. pascal OSErr MyTrackingHandler(short message, WindowPtr duhWindow,
  461.                                void *handlerRefCon, DragReference theDrag)
  462. {    short                result, offset;
  463.     long                theTime = TickCount();
  464.     unsigned short        count, index;
  465.     unsigned long        flavorFlags, attributes;
  466.     ItemReference        theItem;
  467.     RgnHandle            theRgn;
  468.     WindowPtr            theWindow=(WindowPtr)handlerRefCon;
  469.     WindowPtr            hitWindow;
  470.     Point                theMouse, localMouse;
  471.     TEHandle            hTE;
  472.     
  473.     if ((message != dragTrackingEnterHandler) && (!canAcceptItems))
  474.         return(noErr);
  475.  
  476.     hTE=GetWindowTE(theWindow);
  477.     
  478.     GetDragAttributes(theDrag, &attributes);
  479.  
  480.     switch (message) {
  481.  
  482.         case dragTrackingEnterHandler:
  483.  
  484.             //
  485.             //    We get called with this message the first time that a drag enters ANY
  486.             //    window in our application. Check to see if all of the drag items contain
  487.             //    TEXT. We only accept a drag if all of the items in the drag can be accepted.
  488.             //
  489.  
  490.             canAcceptItems = true;
  491.  
  492.             CountDragItems(theDrag, &count);
  493.  
  494.             for (index = 1; index <= count; index++) {
  495.                 GetDragItemReferenceNumber(theDrag, index, &theItem);
  496.  
  497.                 result = GetFlavorFlags(theDrag, theItem, 'TEXT', &flavorFlags);
  498.  
  499.                 if (result != noErr) {
  500.                     canAcceptItems = false;
  501.                     break;
  502.                 }
  503.             }
  504.  
  505.             break;
  506.  
  507.         case dragTrackingEnterWindow:
  508.  
  509.             //
  510.             //    We receive an EnterWindow message each time a drag enters one of our
  511.             //    application's windows. We initialize our global variables for tracking
  512.             //    the drag through the window.
  513.             //
  514.  
  515.             caretTime = theTime;
  516.             caretOffset = lastOffset = -1;
  517.             caretShow = true;
  518.  
  519.             cursorInContent = false;
  520.  
  521.             break;
  522.  
  523.         case dragTrackingInWindow:
  524.  
  525.             //
  526.             //    We receive InWindow messages as long as the mouse is in one of our windows
  527.             //    during a drag. We draw the window highlighting and blink the insertion caret
  528.             //    when we get these messages.
  529.             //
  530.  
  531.             GetDragMouse(theDrag, &theMouse, 0L);
  532.             localMouse = theMouse;
  533.             GlobalToLocal(&localMouse);
  534.  
  535.             //
  536.             //    Show or hide the window highlighting when the mouse enters or leaves the
  537.             //    TextEdit field in our window (we don't want to show the highlighting when
  538.             //    the mouse is over the window title bar or over the scroll bars).
  539.             //
  540.  
  541.             if (attributes & dragHasLeftSenderWindow) {
  542.                 if (PtInRect(localMouse, &(**hTE).viewRect)) {
  543.  
  544.                     if (!cursorInContent)
  545.                     {
  546.                         Rect            temp;
  547.                         
  548.                         temp=GetWindowBounds(theWindow);
  549.                         OffsetRect(&temp, -temp.left, -temp.top);
  550.                         temp.right-=15;
  551.                         temp.bottom-=15;
  552.                         RectRgn(theRgn=NewRgn(), &temp);
  553.                         //RectRgn(theRgn = NewRgn(), &(**hTE).viewRect);
  554.                         ShowDragHilite(theDrag, theRgn, true);
  555.                         DisposeRgn(theRgn);
  556.                     }
  557.                     cursorInContent = true;
  558.  
  559.                 } else {
  560.  
  561.                     if (cursorInContent) {
  562.                         HideDragHilite(theDrag);
  563.                     }
  564.                     cursorInContent = false;
  565.  
  566.                 }
  567.             }
  568.  
  569.             offset = HitTest(theMouse, &hitWindow);
  570.             
  571.             //
  572.             //    If this application is the sender, do not allow tracking through
  573.             //    the selection in the window that sourced the drag.
  574.             //
  575.  
  576.             if (attributes & dragInsideSenderWindow) {
  577.                 if ((offset >= (**hTE).selStart) &&
  578.                     (offset <= (**hTE).selEnd)) {
  579.                         offset = -1;
  580.                 }
  581.             }
  582.  
  583.             if (hitWindow == theWindow) {
  584.  
  585.                 insertPosition = offset;
  586.  
  587.                 //
  588.                 //    Reset flashing counter if the offset has moved. This makes the
  589.                 //    caret blink only after the caret has stopped moving long enough.
  590.                 //
  591.  
  592.                 if (offset != lastOffset) {
  593.                     caretTime = theTime;
  594.                     caretShow = true;
  595.                 }
  596.                 lastOffset = offset;
  597.  
  598.                 //
  599.                 //    Flash caret.
  600.                 //
  601.  
  602.                 if (theTime - caretTime > gCaretTime) {
  603.                     caretShow = !caretShow;
  604.                     caretTime = theTime;
  605.                 }
  606.                 if (! caretShow) {
  607.                     offset = -1;
  608.                 }
  609.  
  610.                 //
  611.                 //    If caret offset has changed, move caret on screen.
  612.                 //
  613.  
  614.                 if (offset != caretOffset) {
  615.                     if (caretOffset != -1) {
  616.                         DrawCaret(caretOffset, hTE);
  617.                     }
  618.                     if (offset != -1) {
  619.                         DrawCaret(offset, hTE);
  620.                     }
  621.                 }
  622.  
  623.                 caretOffset = offset;
  624.  
  625.             } else {
  626.  
  627.                 lastOffset = offset;
  628.                 insertPosition = -1;
  629.  
  630.             }
  631.  
  632.             break;
  633.  
  634.         case dragTrackingLeaveWindow:
  635.  
  636.             //
  637.             //    If the caret is on the screen, remove it.
  638.             //
  639.  
  640.             if (caretOffset != -1) {
  641.                 DrawCaret(caretOffset, hTE);
  642.                 caretOffset = -1;
  643.             }
  644.  
  645.             //
  646.             //    Remove window highlighting, if showing.
  647.             //
  648.  
  649.             if ((cursorInContent) && (attributes & dragHasLeftSenderWindow))
  650.                 HideDragHilite(theDrag);
  651.  
  652.             break;
  653.  
  654.         case dragTrackingLeaveHandler:
  655.             break;
  656.  
  657.     }
  658.  
  659.     return(noErr);
  660. }
  661.  
  662.  
  663. /*
  664.  *    DropLocationIsFinderTrash
  665.  *
  666.  *    Returns true if the given dropLocation AEDesc is a descriptor of the Finder's Trash.
  667.  */
  668.  
  669. Boolean DropLocationIsFinderTrash(AEDesc *dropLocation)
  670. {
  671.     OSErr            result;
  672.     AEDesc            dropSpec;
  673.     FSSpec            *theSpec;
  674.     CInfoPBRec        thePB;
  675.     short            trashVRefNum;
  676.     long            trashDirID;
  677.  
  678.     //
  679.     //    Coerce the dropLocation descriptor to an FSSpec. If there's no dropLocation or
  680.     //    it can't be coerced into an FSSpec, then it couldn't have been the Trash.
  681.     //
  682.  
  683.     if ((dropLocation->descriptorType != typeNull) &&
  684.         (AECoerceDesc(dropLocation, typeFSS, &dropSpec) == noErr)) {
  685.  
  686.         HLock(dropSpec.dataHandle);
  687.         theSpec = (FSSpec *) *dropSpec.dataHandle;
  688.  
  689.         //
  690.         //    Get the directory ID of the given dropLocation object.
  691.         //
  692.  
  693.         thePB.dirInfo.ioCompletion = 0L;
  694.         thePB.dirInfo.ioNamePtr = (StringPtr) &theSpec->name;
  695.         thePB.dirInfo.ioVRefNum = theSpec->vRefNum;
  696.         thePB.dirInfo.ioFDirIndex = 0;
  697.         thePB.dirInfo.ioDrDirID = theSpec->parID;
  698.  
  699.         result = PBGetCatInfo(&thePB, false);
  700.  
  701.         HUnlock(dropSpec.dataHandle);
  702.         AEDisposeDesc(&dropSpec);
  703.  
  704.         if (result != noErr)
  705.             return(false);
  706.  
  707.         //
  708.         //    If the result is not a directory, it must not be the Trash.
  709.         //
  710.  
  711.         if (!(thePB.dirInfo.ioFlAttrib & (1 << 4)))
  712.             return(false);
  713.  
  714.         //
  715.         //    Get information about the Trash folder.
  716.         //
  717.  
  718.         FindFolder(theSpec->vRefNum, kTrashFolderType, kCreateFolder, &trashVRefNum, &trashDirID);
  719.  
  720.         //
  721.         //    If the directory ID of the dropLocation object is the same as the directory ID
  722.         //    returned by FindFolder, then the drop must have occurred into the Trash.
  723.         //
  724.  
  725.         if (thePB.dirInfo.ioDrDirID == trashDirID)
  726.             return(true);
  727.     }
  728.  
  729.     return(false);
  730. }
  731.  
  732.  
  733. /*
  734.  *    Drag the selected text in the given document.
  735.  */
  736.  
  737. Boolean DragText(WindowPtr theWindow, EventRecord *theEvent, RgnHandle hiliteRgn)
  738. {
  739.     short            result;
  740.     RgnHandle        dragRegion, tempRgn;
  741.     Point            theLoc;
  742.     DragReference    theDrag;
  743. #if USE_STYLED_TEXT
  744.     StScrpHandle    theStyl;
  745. #endif
  746.     AEDesc            dropLocation;
  747.     DragAttributes    attributes;
  748.     short            mouseDownModifiers, mouseUpModifiers, copyText;
  749.     TEHandle        hTE;
  750.     
  751.  
  752.     if (!WindowHasLayer(theWindow))
  753.         return FALSE;
  754.     hTE=GetWindowTE(theWindow);
  755.     
  756.     //
  757.     //    Copy the hilite region into dragRegion and offset it into global coordinates.
  758.     //
  759.  
  760.     CopyRgn(hiliteRgn, dragRegion = NewRgn());
  761.     SetPt(&theLoc, 0, 0);
  762.     LocalToGlobal(&theLoc);
  763.     OffsetRgn(dragRegion, theLoc.h, theLoc.v);
  764.  
  765.     //
  766.     //    Wait for the mouse to move to the mouse button to be released. If the mouse button was
  767.     //    released before the mouse moves, return false. Returing false from DragText means that
  768.     //    a drag operation did not occur.
  769.     //
  770.  
  771.     if (! WaitMouseMoved(theEvent->where))
  772.     {
  773.         return FALSE;
  774.     }
  775.  
  776.     NewDrag(&theDrag);
  777.  
  778.     //
  779.     //    For purposes of demonstration, we insert the 'TEXT' data and promise 'styl'
  780.     //    data. If a receiver requests 'TEXT', the Drag Manager will give them the text
  781.     //    without needing us to intervene. If a receiver requests 'styl', the Drag Manager
  782.     //    will call our MySendDataProc to provide the data at drop time. The MySendDataProc
  783.     //    is specified by calling SetDragSendProc.
  784.     //
  785.  
  786.     AddDragItemFlavor(theDrag, 1, 'TEXT', GetSelectedTextPtr(theWindow),
  787.                       GetSelectionSize(theWindow), 0);
  788.  
  789. #if USE_STYLED_TEXT
  790.     theStyl = GetStylScrap(hTE);
  791.     HLock((Handle) theStyl);
  792.     AddDragItemFlavor(theDrag, 1, 'styl', (Ptr) *theStyl, GetHandleSize((Handle) theStyl), 0);
  793.     HUnlock((Handle) theStyl);
  794.     DisposeHandle((Handle) theStyl);
  795.  
  796.     SetDragSendProc(theDrag, MySendDataProc, (void *)theWindow);
  797. #endif
  798.  
  799.     //
  800.     //    Set the item's bounding rectangle in global coordinates.
  801.     //
  802.  
  803.     SetDragItemBounds(theDrag, 1, &(**dragRegion).rgnBBox);
  804.  
  805.     //
  806.     //    Prepare the drag region.
  807.     //
  808.  
  809.     tempRgn = NewRgn();
  810.     CopyRgn(dragRegion, tempRgn);
  811.     InsetRgn(tempRgn, 1, 1);
  812.     DiffRgn(dragRegion, tempRgn, dragRegion);
  813.     DisposeRgn(tempRgn);
  814.  
  815.     //
  816.     //    Drag the text. TrackDrag will return userCanceledErr if the drop zoomed-back
  817.     //    for any reason.
  818.     //
  819.  
  820.     result = TrackDrag(theDrag, theEvent, dragRegion);
  821.  
  822.     if (result != noErr && result != userCanceledErr)
  823.     {
  824.         return TRUE;
  825.     }
  826.  
  827.     //
  828.     //    Check to see if the drop occurred in the Finder's Trash. If the drop occurred
  829.     //    in the Finder's Trash and a copy operation wasn't specified, delete the
  830.     //    source selection. Note that we can continute to get the attributes, drop location
  831.     //    modifiers, etc. of the drag until we dispose of it using DisposeDrag.
  832.     //
  833.  
  834.     GetDragAttributes(theDrag, &attributes);
  835.     if (!(attributes & dragInsideSenderApplication))
  836.     {
  837.         GetDropLocation(theDrag, &dropLocation);
  838.  
  839.         GetDragModifiers(theDrag, 0L, &mouseDownModifiers, &mouseUpModifiers);
  840.         copyText = (mouseDownModifiers | mouseUpModifiers) & optionKey;
  841.  
  842.         if ((!copyText) && (DropLocationIsFinderTrash(&dropLocation)))
  843.         {
  844.             TEDelete(hTE);
  845.             SetWindowIsModified(theWindow, TRUE);
  846.         }
  847.  
  848.         AEDisposeDesc(&dropLocation);
  849.     }
  850.  
  851.     //
  852.     //    Dispose of the drag.
  853.     //
  854.  
  855.     DisposeDrag(theDrag);
  856.  
  857.     DisposeRgn(dragRegion);
  858.  
  859.     return TRUE;
  860. }
  861.  
  862. Boolean DragInWindow(WindowPtr theWindow, EventRecord *theEvent)
  863. /* returns TRUE if drag occurred in window, FALSE otherwise */
  864. {
  865.     Point            thePoint;
  866.     RgnHandle        hiliteRgn;
  867.     
  868.     if (!DragManagerAvailableQQ())
  869.         return FALSE;
  870.     
  871.     if (!WindowIsDraggableQQ(theWindow))
  872.         return FALSE;
  873.     
  874.     if (GetWindowTE(theWindow)==0L)
  875.         return FALSE;
  876.     
  877.     hiliteRgn=GetWindowHiliteRgn(theWindow);
  878.     
  879.     SetPort(theWindow);
  880.     thePoint = theEvent->where;
  881.     GlobalToLocal(&thePoint);
  882.  
  883.     if (PtInRgn(thePoint, hiliteRgn))
  884.     {
  885.         return DragText(theWindow, theEvent, hiliteRgn);
  886.     }
  887.     
  888.     return FALSE;
  889. }
  890.  
  891. void ResetHiliteRgn(WindowPtr theWindow)
  892. {
  893.     TEHandle        hTE;
  894.     RgnHandle        hiliteRgn;
  895.     
  896.     if ((!DragManagerAvailableQQ()) || (theWindow==0L) || (!WindowIsDraggableQQ(theWindow)) ||
  897.         ((hTE=GetWindowTE(theWindow))==0L))
  898.         return;
  899.     
  900.     hiliteRgn=GetWindowHiliteRgn(theWindow);
  901.     if (hiliteRgn==0L)
  902.         hiliteRgn=NewRgn();
  903.     TEGetHiliteRgn(hiliteRgn, hTE);
  904.     SetWindowHiliteRgn(theWindow, hiliteRgn);
  905. }
  906.  
  907. Boolean CursorInDraggableRgn(Point thePoint, WindowPtr theWindow)
  908. {
  909.     RgnHandle        hiliteRgn;
  910.     
  911.     if ((!DragManagerAvailableQQ()) || (theWindow==0L) || (!WindowIsDraggableQQ(theWindow)))
  912.         return FALSE;
  913.     
  914.     hiliteRgn=GetWindowHiliteRgn(theWindow);
  915.     return (PtInRgn(thePoint, hiliteRgn));
  916. }
  917.